Bind

Bind可用于绑定函数、成员函数、函数对象、成员变量,bind函数支持最多10个自定义参数

1
2
3
4
int f(int a, int b) {
return a + b;
}
std::bind(f, 5, std::placeholders::_1)(x); // 相当于执行了f(5, x);

在上面这段代码中:

  • std::bind函数返回绑定对象,后面跟的(x)表示传参x并执行;
  • std::placeholders::_1是占位符,表示调用时的第一个参数,这段代码里表示x;
  • 如果代码是std::bind(f, std::placeholders::_2, std::placeholders::_1)(x, y)则表示执行f(y, x)
  • 调用前传入的函数参数会被复制并保存在std::bind返回的对象中,比如之前的std::bind(f, 5, std::placeholders::_1)中的5就被存储在了返回的对象中,所以为了性能上考虑,建议传入的类型为引用或指针,避免结构复制

Bind和类成员函数

此时需要注意的是成员函数绑定的第二个参数必须是类实例:

1
2
3
4
5
6
7
8
9
10
struct X {
bool f(int a);
};
X x;
std::shared_ptr<X> p(new X);
int i = 5;
std::bind(&X::f, ref(x), std::placeholders::_1)(i); //相当于执行了x.f(i)
std::bind(&X::f, &x, std::placeholders::_1)(i); // 相当于执行了(&x)->f(i)
std::bind(&X::f, x, std::placeholders::_1)(i); // 复制x,并执行(复制的x).f(i)
std::bind(&X::f, p, std::placeholders::_1)(i); //复制智能指针p,并执行(复制的p)->f(i)

由于第二个参数的类实例的保存方式与参数一致,所以也建议传入类引用或类指针,或者智能指针

bind举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <cstdio>
#include <memory>
#include <functional>
class Button {
public:
std::function<void(int)> onClick;
};
class Player{
public:
void play(void* sender, int param) {
printf("Play: %d => %d\n", (int)sender, param);
}
void stop(void* sender, int param) {
printf("Play: %d => %d\n", (int)sender, param);
}
};
Button playButton, stopButton;
Player thePlayer;
void connect() {
playButton.onClick = std::Bind(&Player::play, &thePlayer, &playButton, std::placeholders::_1);
stopButton.onClick = std::Bind(&Player::stop, &thePlayer, &stopButton, std::placeholders::_1);
}
int main() {
connect();
playButton.onClick(0);
return 0;
}

上面这段程序其实就是bind在回调函数中的用法,Button类中有一个回调函数onClick(),需要根据不同的场合实现不同的功能,使用bind函数为playButton绑定了play()函数,而为stopButton绑定了stop()函数,这是bind()函数在回调这方面的一个典型用法。